{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 基于矩阵分解的协同过滤"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#导入必要的工具包\n",
    "import pandas as pd\n",
    "import numpy as np\n",
    "\n",
    "import pickle\n",
    "import scipy.io as sio\n",
    "\n",
    "import scipy.spatial.distance as ssd\n",
    "\n",
    "from numpy.random import random"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "ename": "NameError",
     "evalue": "name 'pickle' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mNameError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-1-24454407b37f>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0;31m#读入数据做初始化\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0muser_index\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mpickle\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mload\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"user_index.pkl\"\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'rb'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      3\u001b[0m \u001b[0mitem_index\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mpickle\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mload\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"item_index.pkl\"\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'rb'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      4\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      5\u001b[0m \u001b[0mn_users\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0muser_index\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mNameError\u001b[0m: name 'pickle' is not defined"
     ]
    }
   ],
   "source": [
    "#读入数据做初始化\n",
    "user_index = pickle.load(open(\"user_index.pkl\",'rb'))\n",
    "item_index = pickle.load(open(\"item_index.pkl\",'rb'))\n",
    "\n",
    "n_users = len(user_index)\n",
    "n_items = len(item_index)\n",
    "\n",
    "#用户-物品关系矩阵\n",
    "user_item_scores = sio.mmread(\"user_items_scores\").todense()\n",
    "\n",
    "#倒排表\n",
    "user_items = pickle.load(open(\"user_items.pkl\",'rb'))\n",
    "item_users = pickle.load(open(\"item_users.pkl\",'rb'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "train = pd.read_csv('./triplet_dataset_sub.csv')\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(22511, 3)"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "\n",
    "#将数据分割训练数据与测试数据\n",
    "from sklearn.model_selection import train_test_split\n",
    "\n",
    "# 随机采样20%的数据构建测试样本，其余作为训练样本\n",
    "train, test = train_test_split(train, random_state=33, test_size=0.4)\n",
    "train.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "#每个用户的总播放次数\n",
    "triplet_train_sum_df = train[['user','play_count']].groupby('user').sum().reset_index()\n",
    "triplet_train_sum_df.rename(columns={'play_count':'total_play_count'},inplace=True)\n",
    "\n",
    "#每首歌曲的播放比例\n",
    "train = pd.merge(train,triplet_train_sum_df)\n",
    "train['fractional_play_count'] = train['play_count']/train['total_play_count']\n",
    "del triplet_train_sum_df"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>user</th>\n",
       "      <th>song</th>\n",
       "      <th>play_count</th>\n",
       "      <th>total_play_count</th>\n",
       "      <th>fractional_play_count</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>30cc99a1b03a19cc162b286c76047e58371ffb3d</td>\n",
       "      <td>SOOXJDU12A8AE47ECB</td>\n",
       "      <td>1</td>\n",
       "      <td>43</td>\n",
       "      <td>0.023256</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>30cc99a1b03a19cc162b286c76047e58371ffb3d</td>\n",
       "      <td>SOTORXA12A58A79338</td>\n",
       "      <td>1</td>\n",
       "      <td>43</td>\n",
       "      <td>0.023256</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>30cc99a1b03a19cc162b286c76047e58371ffb3d</td>\n",
       "      <td>SODJWHY12A8C142CCE</td>\n",
       "      <td>1</td>\n",
       "      <td>43</td>\n",
       "      <td>0.023256</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>30cc99a1b03a19cc162b286c76047e58371ffb3d</td>\n",
       "      <td>SOWSSRH12A58A7CE5D</td>\n",
       "      <td>1</td>\n",
       "      <td>43</td>\n",
       "      <td>0.023256</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>30cc99a1b03a19cc162b286c76047e58371ffb3d</td>\n",
       "      <td>SOXPDDQ12A58A76829</td>\n",
       "      <td>1</td>\n",
       "      <td>43</td>\n",
       "      <td>0.023256</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                                       user                song  play_count  \\\n",
       "0  30cc99a1b03a19cc162b286c76047e58371ffb3d  SOOXJDU12A8AE47ECB           1   \n",
       "1  30cc99a1b03a19cc162b286c76047e58371ffb3d  SOTORXA12A58A79338           1   \n",
       "2  30cc99a1b03a19cc162b286c76047e58371ffb3d  SODJWHY12A8C142CCE           1   \n",
       "3  30cc99a1b03a19cc162b286c76047e58371ffb3d  SOWSSRH12A58A7CE5D           1   \n",
       "4  30cc99a1b03a19cc162b286c76047e58371ffb3d  SOXPDDQ12A58A76829           1   \n",
       "\n",
       "   total_play_count  fractional_play_count  \n",
       "0                43               0.023256  \n",
       "1                43               0.023256  \n",
       "2                43               0.023256  \n",
       "3                43               0.023256  \n",
       "4                43               0.023256  "
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "train.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "#初始化模型参数\n",
    "K=20"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "#初始化参数\n",
    "bi = np.zeros(n_items)\n",
    "bu = np.zeros(n_users)\n",
    "\n",
    "P = random((n_users,K))/10*(np.sqrt(K))\n",
    "Q = random((K,n_items))/10*(np.sqrt(K))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "ename": "IndexError",
     "evalue": "index 20249 is out of bounds for axis 1 with size 800",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mIndexError\u001b[0m                                Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-9-56b7e88105e5>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m     14\u001b[0m     \u001b[0mi_ids\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0miid\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     15\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 16\u001b[0;31m     \u001b[0mR\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0muid\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0miid\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mtrain\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0miloc\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'fractional_play_count'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     17\u001b[0m     \u001b[0mmu\u001b[0m \u001b[0;34m+=\u001b[0m \u001b[0mR\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0muid\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0miid\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     18\u001b[0m \u001b[0mmu\u001b[0m \u001b[0;34m/=\u001b[0m \u001b[0mn_samples\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mIndexError\u001b[0m: index 20249 is out of bounds for axis 1 with size 800"
     ]
    }
   ],
   "source": [
    "#读入训练数据\n",
    "n_samples = train.shape[0]\n",
    "\n",
    "mu = 0.0\n",
    "uids = []\n",
    "i_ids = []\n",
    "\n",
    "R = np.matrix(np.zeros(shape=(n_users,n_items)), float)\n",
    "\n",
    "for i in range(n_samples):\n",
    "    uid = user_index[train.iloc[i]['user']]\n",
    "    iid = item_index[train.iloc[i]['song']]\n",
    "    \n",
    "    uids.append(uid)\n",
    "    i_ids.append(iid)\n",
    "    \n",
    "    R[uid,iid] = train.iloc[i]['fractional_play_count']\n",
    "    mu += R[uid,iid]\n",
    "mu /= n_samples\n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "#迭代、随机梯度下降\n",
    "def pred_SVD(uid,i_id):\n",
    "    score = mu + bi[i_id] + bu[uid] +np.dot(P[uid,:],Q[:,i_id])\n",
    "    return score"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "the  0 -th step is running\n"
     ]
    },
    {
     "ename": "IndexError",
     "evalue": "list index out of range",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mIndexError\u001b[0m                                Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-11-60a5ceca5132>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m     12\u001b[0m         \u001b[0mindex\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mkk\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mj\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     13\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 14\u001b[0;31m         \u001b[0muid\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0muids\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mindex\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     15\u001b[0m         \u001b[0miid\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mi_ids\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mindex\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     16\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mIndexError\u001b[0m: list index out of range"
     ]
    }
   ],
   "source": [
    "n_steps  =50\n",
    "gamma = 0.04\n",
    "Lambda = 0.15\n",
    "\n",
    "for step in range(n_steps):\n",
    "    print('the ',step,'-th step is running')\n",
    "    \n",
    "    rmse_sum = 0.0\n",
    "    \n",
    "    kk = np.random.permutation(n_samples)\n",
    "    for j in range(n_samples):\n",
    "        index = kk[j]\n",
    "        \n",
    "        uid = uids[index]\n",
    "        iid = i_ids[index]\n",
    "        \n",
    "        eui = R[uid,iid] - pred_SVD(uid,iid)\n",
    "        \n",
    "        rmse_sum += eui**2\n",
    "        \n",
    "        bu[uid] += gamma*(eui - Lambda*bu[uid])\n",
    "        bi[iid]+= gamma*(eui- Lambda*bi[iid])\n",
    "        \n",
    "        for k in range(K):\n",
    "            temp = P[uid,k] + gamma *eui*Q[k,iid] - Lambda * P[uid,k]\n",
    "            Q[k,iid] += gamma *eui *P[uid,k] - Lambda * Q[k,iid]\n",
    "            P[uid,k] = temp\n",
    "    gamma = gamma*0.93\n",
    "    print(\"the rmse of the {} th step on train data is:{}\".format(step,rmse_sum))\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "#计算用户对每个item的预测打分\n",
    "cur_user = '90d2fcb1dbe47dc1e9442587e259811a0437a13f'\n",
    "cur_user_id = user_index[cur_user]\n",
    "cur_user_items = user_items[cur_user_id]\n",
    "\n",
    "sim_accumulate = 0.0\n",
    "rat_acc = 0.0\n",
    "\n",
    "user_items_scores = np.zeros(n_items)\n",
    "\n",
    "for i in range(n_items):\n",
    "    if i not in cur_user_items:\n",
    "        user_items_scores[i] = pred_SVD(cur_user_id,i)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([1.16789861, 0.96441197, 1.21878428, 1.04407921, 1.19823667,\n",
       "       1.45265849, 1.27270083, 1.19940258, 1.02715387, 1.33961986,\n",
       "       1.01913746, 1.54054865, 1.18123284, 1.13453178, 1.15094099,\n",
       "       1.28474508, 1.12667816, 1.04344269, 1.078     , 1.12629613,\n",
       "       1.10495042, 1.19405881, 0.91674972, 1.12478988, 1.28672519,\n",
       "       1.13982453, 1.13501482, 1.17408412, 1.26335513, 1.03392746,\n",
       "       1.14090439, 1.32130161, 1.4517245 , 1.19408521, 1.27313695,\n",
       "       0.95840112, 1.10093492, 1.15656254, 1.09937482, 1.19214355,\n",
       "       1.33747678, 1.02918919, 0.78950657, 1.4189262 , 1.29717044,\n",
       "       1.28485504, 1.31835795, 1.23792142, 0.97553201, 1.07038043,\n",
       "       1.14667594, 1.09050942, 1.38813424, 1.25910344, 1.21531683,\n",
       "       1.16894777, 1.21100006, 1.1175257 , 1.12656102, 1.26667988,\n",
       "       1.14764088, 1.05352183, 1.13906178, 1.01967432, 1.36425431,\n",
       "       1.40369084, 1.09506348, 1.0979762 , 0.89184864, 1.29267504,\n",
       "       1.26206412, 1.2062734 , 1.15202042, 1.27228791, 1.11884291,\n",
       "       1.0461841 , 1.07449395, 1.13845481, 1.34092698, 1.31821842,\n",
       "       1.23298381, 1.16557178, 1.16818066, 1.13556831, 1.03323402,\n",
       "       1.25556003, 1.21946798, 1.31864894, 1.55080164, 1.49823891,\n",
       "       1.05028663, 1.13844725, 1.16031254, 1.43207981, 1.08421241,\n",
       "       1.05205541, 0.84053506, 1.2404837 , 1.18021105, 1.33735513,\n",
       "       0.97558134, 1.22941647, 1.23566601, 0.96417854, 1.00279912,\n",
       "       0.93601205, 1.16196824, 1.29310584, 1.13509559, 1.03801906,\n",
       "       1.07128455, 1.2141403 , 0.83736573, 0.96007436, 1.35575495,\n",
       "       1.53260577, 1.08486067, 1.22621904, 1.0506175 , 1.18264528,\n",
       "       1.33696202, 1.3582507 , 0.83619605, 1.16989639, 1.15204096,\n",
       "       1.15629537, 1.13744546, 1.23569273, 1.18132195, 1.22775942,\n",
       "       1.26780461, 1.20239756, 1.15892131, 1.00079014, 1.57960517,\n",
       "       1.12183609, 1.38519033, 1.18033007, 1.1898495 , 1.3253868 ,\n",
       "       1.12639348, 1.09054817, 1.38278234, 1.29347924, 1.37547523,\n",
       "       1.47201192, 0.86168059, 1.14848729, 1.12886344, 1.07287867,\n",
       "       1.12880402, 1.198158  , 0.85239729, 1.50528786, 1.40330673,\n",
       "       1.31462312, 1.28929865, 1.05979695, 1.18512564, 1.47270443,\n",
       "       1.42162813, 1.40054424, 1.32278118, 1.18986848, 1.00539216,\n",
       "       1.33349129, 1.23335004, 1.32182844, 1.44787908, 1.27426412,\n",
       "       1.23140102, 1.2537469 , 1.11631816, 1.07578774, 1.37292361,\n",
       "       1.21630406, 1.0542722 , 1.15291889, 1.10404915, 1.17681297,\n",
       "       1.22322649, 1.4779059 , 1.11055406, 1.26368604, 1.18763673,\n",
       "       1.09711079, 1.71481886, 1.18135044, 0.89701342, 1.3364317 ,\n",
       "       1.19804041, 1.39513893, 0.93202894, 1.42014995, 1.0943876 ,\n",
       "       1.26327794, 1.43479647, 1.13557119, 1.18919231, 1.05385754,\n",
       "       1.26221065, 1.38492116, 1.09532946, 1.3628445 , 1.3757579 ,\n",
       "       1.3610239 , 1.52405175, 1.1469819 , 1.16518905, 1.21219608,\n",
       "       1.38819184, 1.18929602, 1.2187819 , 1.14506528, 1.09338356,\n",
       "       1.18238031, 1.19241946, 1.03925346, 1.4703227 , 1.112825  ,\n",
       "       1.30524998, 1.13079878, 1.27529036, 1.44131151, 1.27893398,\n",
       "       1.37072211, 1.02899962, 1.11693832, 1.17997646, 1.20888215,\n",
       "       1.39405958, 1.4486029 , 1.1941437 , 1.12637905, 1.29426858,\n",
       "       1.31444489, 0.96935107, 1.28772594, 0.93589849, 1.296328  ,\n",
       "       1.30590458, 1.32968788, 1.41421801, 1.3379983 , 1.32361824,\n",
       "       1.42401454, 1.19404438, 1.58430675, 1.03403756, 1.29053165,\n",
       "       0.99795788, 1.25262884, 1.1946963 , 1.25038931, 1.16085745,\n",
       "       1.33263439, 1.53648942, 1.21644835, 1.45156522, 1.01696643,\n",
       "       1.1765617 , 1.34371858, 1.19484288, 1.10331975, 0.77548434,\n",
       "       0.91883877, 1.25847338, 1.20914765, 0.91703618, 1.1012495 ,\n",
       "       0.95514394, 1.22740851, 1.01997874, 1.38149995, 1.38031834,\n",
       "       1.26924327, 1.29779581, 1.31534308, 1.28697448, 1.75204989,\n",
       "       1.40170235, 1.43221139, 1.2846021 , 1.25503796, 1.24673129,\n",
       "       0.99472063, 0.98844118, 0.98511589, 1.49718495, 0.99512993,\n",
       "       1.4431699 , 0.98210857, 1.25891876, 1.06312038, 1.24325879,\n",
       "       1.08257698, 1.08531924, 1.45860205, 1.1536405 , 1.01236911,\n",
       "       1.25175371, 1.0794303 , 1.4322823 , 1.21227286, 1.13166068,\n",
       "       1.12624954, 1.22880783, 1.19785841, 1.05456666, 1.40893218,\n",
       "       1.21618492, 1.25545451, 1.09337205, 1.1222118 , 1.28426417,\n",
       "       1.31429513, 1.34478205, 0.98855718, 0.84246691, 1.09186937,\n",
       "       1.36138427, 1.22948305, 1.45700539, 1.24891903, 1.28563044,\n",
       "       0.97954231, 1.58078611, 1.20986999, 1.05746074, 1.10943434,\n",
       "       0.9011078 , 0.9720159 , 1.15498711, 1.43127139, 1.10908837,\n",
       "       1.35800607, 1.35972851, 0.88854646, 1.20173906, 0.85956164,\n",
       "       1.33566792, 1.09542722, 1.23917322, 1.46768958, 1.25584201,\n",
       "       1.38438269, 1.22228155, 1.21570689, 1.44697135, 1.07257795,\n",
       "       1.58448282, 1.21950495, 1.1446827 , 0.92046358, 1.1483905 ,\n",
       "       1.45513194, 1.05373918, 1.42882492, 1.06303218, 1.19157685,\n",
       "       1.21644069, 1.07302786, 1.10030265, 1.11895164, 1.245286  ,\n",
       "       1.03442   , 1.14296617, 0.89845089, 1.14566154, 1.28717916,\n",
       "       0.96502712, 1.06092791, 0.98504604, 0.8091322 , 1.59212672,\n",
       "       1.5211202 , 0.78588863, 1.12680548, 1.34419851, 1.03453989,\n",
       "       0.93835117, 1.19721351, 0.90962508, 1.08418959, 1.1672712 ,\n",
       "       1.46808268, 1.26798688, 1.02598685, 1.45626875, 1.054726  ,\n",
       "       1.24528364, 1.11598581, 1.13769132, 1.41833784, 1.25737634,\n",
       "       1.10006677, 1.2726942 , 1.28035507, 1.2476234 , 1.39189951,\n",
       "       1.45453862, 1.1085577 , 1.12013398, 1.08985283, 0.95247524,\n",
       "       1.0214884 , 1.24669613, 1.36315733, 1.15414532, 1.12631986,\n",
       "       1.22379928, 1.20058146, 1.4359248 , 1.08155037, 1.03451373,\n",
       "       0.99831598, 1.38039747, 1.09264522, 1.53833353, 1.16594677,\n",
       "       1.05370153, 1.0912404 , 1.23431303, 1.39460063, 1.45021135,\n",
       "       1.07794449, 0.84683841, 1.43121581, 1.19311683, 1.05586175,\n",
       "       1.15539727, 1.04609299, 1.16918409, 1.37503977, 0.92395968,\n",
       "       1.90155664, 1.51633932, 1.10764275, 1.29159064, 1.12286742,\n",
       "       1.49313556, 1.18650709, 1.22456196, 1.2004808 , 1.31394803,\n",
       "       0.93134666, 1.08886344, 1.09563241, 1.15768884, 1.38225344,\n",
       "       1.0973498 , 1.28928716, 1.09376976, 1.37549886, 1.42600648,\n",
       "       1.60421709, 1.01675032, 1.37550096, 1.08456861, 1.19353611,\n",
       "       1.21360516, 1.02195672, 1.24754157, 0.92025697, 1.28310834,\n",
       "       1.37715332, 1.22544716, 1.25552864, 1.24729191, 1.07757061,\n",
       "       1.1815102 , 1.04231949, 1.29504135, 1.04867389, 1.27271404,\n",
       "       1.20281202, 1.06910765, 1.12858004, 1.29542252, 1.22879161,\n",
       "       0.99329567, 1.42112815, 1.21084466, 1.19301096, 1.32050463,\n",
       "       1.13506686, 1.19305737, 1.03252612, 0.97020799, 0.98012407,\n",
       "       1.13168343, 1.20280448, 1.18110402, 0.95680604, 1.24907001,\n",
       "       1.02930545, 1.32954984, 1.25807597, 1.15407784, 1.28456505,\n",
       "       1.51590038, 1.21552168, 1.08510697, 1.30951734, 1.50064268,\n",
       "       1.07122882, 1.08588567, 0.97592187, 1.08876844, 1.33018523,\n",
       "       1.19231451, 1.19764215, 1.02100197, 1.03530128, 1.2934579 ,\n",
       "       1.3053638 , 1.2938063 , 1.22064278, 1.3548266 , 1.29830615,\n",
       "       1.11600179, 1.08927315, 1.21415195, 1.32992668, 1.22892885,\n",
       "       1.22398556, 0.86435679, 0.88703937, 1.39389392, 1.1993448 ,\n",
       "       1.32865187, 1.46770874, 1.28748046, 1.31601541, 1.09634106,\n",
       "       1.0776267 , 1.44776818, 0.98107355, 1.56930508, 1.23081266,\n",
       "       1.10950943, 1.03668389, 1.36415251, 1.12012842, 1.02451043,\n",
       "       1.29348513, 1.17618518, 0.92737114, 1.08982248, 1.27564977,\n",
       "       1.0893526 , 1.2163899 , 1.08000966, 0.97414844, 1.27234577,\n",
       "       1.28311661, 1.39773219, 0.99715663, 0.94564763, 1.0195681 ,\n",
       "       1.0840566 , 1.30631226, 1.51022619, 1.31276198, 1.54359813,\n",
       "       1.26337155, 1.12918674, 1.26099168, 1.20354572, 0.96160246,\n",
       "       1.24945276, 1.19134802, 1.38016083, 1.14954929, 1.22163217,\n",
       "       1.21449805, 0.87493361, 1.31365665, 1.31490397, 1.25156657,\n",
       "       1.01521749, 1.43563565, 1.19457856, 1.43828347, 1.19498322,\n",
       "       1.34281421, 1.49235554, 1.29115336, 1.32437354, 0.98238547,\n",
       "       1.51759117, 1.30395326, 1.558046  , 1.51127732, 1.17022582,\n",
       "       1.299505  , 1.31253884, 1.20113814, 1.06396997, 0.81032814,\n",
       "       1.15253962, 1.55818709, 1.11836719, 1.0276534 , 1.12371517,\n",
       "       1.42001769, 1.05206988, 1.39113187, 1.1894957 , 1.05085433,\n",
       "       1.23006985, 1.11032383, 1.19275036, 0.84377116, 1.37370481,\n",
       "       1.07972768, 1.21692221, 1.30406691, 1.16164039, 1.35276663,\n",
       "       1.36645915, 1.43117604, 1.12551654, 1.40142271, 1.03516103,\n",
       "       1.10429129, 1.15333687, 1.11359913, 1.5851867 , 0.97652155,\n",
       "       1.72369281, 1.26551248, 1.03927788, 0.92779244, 1.27255311,\n",
       "       1.1690678 , 1.06767473, 0.9539148 , 1.07195662, 1.22929012,\n",
       "       1.15162582, 1.190761  , 1.20905086, 1.03598765, 1.38782266,\n",
       "       1.1595615 , 1.19467937, 1.30014122, 1.35426483, 1.48076357,\n",
       "       1.31952537, 0.98251132, 1.19154595, 1.26439005, 1.24172948,\n",
       "       1.39648328, 1.33537285, 1.49173981, 1.55826126, 1.2381469 ,\n",
       "       1.37921987, 1.21454673, 1.19096882, 1.04630206, 1.02623478,\n",
       "       1.49710237, 1.07342532, 0.99930924, 0.91990695, 1.15872506,\n",
       "       1.1926205 , 1.23766113, 1.0698051 , 1.40484924, 1.07109439,\n",
       "       1.17116834, 1.2511192 , 0.99151667, 1.12562352, 1.21889288,\n",
       "       1.13404067, 1.4668495 , 1.20691574, 1.4059512 , 1.29996374,\n",
       "       1.33591288, 1.35928546, 1.12335249, 1.37386173, 0.77003106,\n",
       "       1.17578001, 1.33563457, 1.25036755, 1.26977426, 1.03521309,\n",
       "       1.15683507, 1.47909685, 1.2882445 , 1.3766253 , 1.21722885,\n",
       "       1.04661014, 1.15241177, 1.17420882, 1.32028546, 1.15531241,\n",
       "       1.22707993, 1.0275707 , 1.352909  , 1.3842058 , 1.34416598,\n",
       "       1.21935337, 1.22140289, 1.12545138, 1.29879232, 1.11645377,\n",
       "       1.26559458, 1.25383105, 1.05306676, 1.09606649, 1.14133192,\n",
       "       1.20066946, 0.96694738, 1.31699276, 1.3016403 , 1.19678439,\n",
       "       1.40549729, 1.32449457, 1.1871573 , 1.12925731, 1.05905737,\n",
       "       1.13706884, 0.95527431, 1.21222929, 1.40106256, 1.23082149,\n",
       "       1.29707692, 1.35147045, 1.4381735 , 1.28922479, 1.13149719,\n",
       "       0.91574093, 1.212687  , 1.27302758, 1.28852354, 1.14591233,\n",
       "       1.53404776, 1.30876714, 0.98334776, 1.35881017, 1.16100112,\n",
       "       1.43788235, 1.075304  , 1.28856147, 0.97547667, 1.15201945,\n",
       "       1.16452431, 1.11537211, 1.56653309, 1.29034672, 1.32785629,\n",
       "       1.10071086, 1.21217206, 1.17666833, 1.20598003, 1.10177554,\n",
       "       1.25911121, 1.45414129, 1.09013589, 0.93830645, 1.12386989,\n",
       "       1.46547465, 1.48258425, 1.03211473, 1.49756989, 1.26359213,\n",
       "       1.32358871, 1.38251916, 1.33735762, 1.07990409, 1.14173292,\n",
       "       1.2367786 , 1.59664006, 1.48021947, 1.3074222 , 1.32137381,\n",
       "       1.25427185, 1.19519986, 1.03511654, 1.10133878, 1.05511238,\n",
       "       1.24215806, 0.99288618, 1.07746492, 1.5003243 , 1.1328053 ,\n",
       "       1.48373162, 1.22862545, 1.30386671, 1.49953166, 1.12487171])"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "user_items_scores"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "ename": "ValueError",
     "evalue": "435 is not in list",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mValueError\u001b[0m                                Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-14-5a41f38bb9cc>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m      7\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mi\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msort_index\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      8\u001b[0m     \u001b[0mcur_item_index\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0msort_index\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 9\u001b[0;31m     \u001b[0mcur_item\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mlist\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mitem_index\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mkeys\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0mlist\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mitem_index\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mvalues\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mindex\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mcur_item_index\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     10\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     11\u001b[0m     \u001b[0;32mif\u001b[0m \u001b[0;34m-\u001b[0m\u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0misnan\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0msort_index\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0mcur_item_index\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mcur_user_items\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0mrank\u001b[0m \u001b[0;34m<=\u001b[0m\u001b[0;36m20\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mValueError\u001b[0m: 435 is not in list"
     ]
    }
   ],
   "source": [
    "#根据用户对item的预测打分产生top推荐\n",
    "sort_index = sorted(((e,i) for i,e in enumerate(list(user_items_scores))), reverse=True)\n",
    "\n",
    "columns = ['user_id','item','score','rank']\n",
    "df = pd.DataFrame(columns=columns)\n",
    "\n",
    "rank=1\n",
    "for i in range(0,len(sort_index)):\n",
    "    cur_item_index = sort_index[i][1]\n",
    "    cur_item = list (item_index.keys()) [list(item_index.values()).index (cur_item_index)]\n",
    "    \n",
    "    if -np.isnan(sort_index[i][0]) and cur_item_index not in cur_user_items and rank <=20:\n",
    "        df.loc[len(df)]=[cur_user,cur_item,sort_index[i][0],rank]\n",
    "        rank = rank+1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>user_id</th>\n",
       "      <th>item</th>\n",
       "      <th>score</th>\n",
       "      <th>rank</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "Empty DataFrame\n",
       "Columns: [user_id, item, score, rank]\n",
       "Index: []"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
